﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NumericalMethod
{
    public enum BasedType
    {
        base10 = 10,
        base2 = 2,
        base8 = 8,
        base16 = 16,
        binaryFraction = 0,
        decimalFraction = 1
    }
    public class Numbers
    {
        const int base10 = 10;
        static char[] cHexa = new char[] { 'A', 'B', 'C', 'D', 'E', 'F' };
        static int[] iHexaNumeric = new int[] { 10, 11, 12, 13, 14, 15 };
        static int[] iHexaIndices = new int[] { 0, 1, 2, 3, 4, 5 };
        const int asciiDiff = 48;
        //static IDictionary<string> dHexa = cHexa.ToList<string>();
        public static string DecimalToBase(decimal iDec, int numbase)
        {
            string strBin = "";
            int[] result = new int[32];
            int MaxBit = 32;
            string[] sDec = iDec.ToString().Split('.');
            int dec = int.Parse(sDec[0].ToString());
            for (; dec > 0; dec /= numbase)
            {
                int rem = dec % numbase;
                result[--MaxBit] = rem;
            }
            for (int i = 0; i < result.Length; i++)
                if ((int)result.GetValue(i) >= base10)
                    strBin += cHexa[(int)result.GetValue(i) % base10];
                else
                    strBin += result.GetValue(i);

            strBin = strBin.TrimStart(new char[] { '0' });

            if (sDec.Length > 1)
            {

            }
            return strBin;
        }
        public static decimal BaseToDecimal(string sBase, int numbase)
        {
            decimal dec = 0;
            decimal frac = 0;
            int b;
            int iProduct = 1;
            string sHexa = "";
            sBase = sBase.ToUpper();
            string[] sFraction = sBase.Split('.');
            
            if (numbase > base10)
                for (int i = 0; i < cHexa.Length; i++)
                    sHexa += cHexa.GetValue(i).ToString();
            for (int i = sFraction[0].Length - 1; i >= 0; i--, iProduct *= numbase)
            {
                string sValue = sFraction[0][i].ToString();
                if (sValue.IndexOfAny(cHexa) >= 0)
                    b = iHexaNumeric[sHexa.IndexOf(sBase[i])];
                else
                    b = (int)sFraction[0][i] - asciiDiff;
                dec += (b * iProduct);
            }

            if (sFraction.Length > 1)
            {
                decimal result = 0;
                for (int i = 0; i < sFraction[1].Length; i++)
                {
                    double iPow = i - ((2 * i) + 1);
                    string sValue = sFraction[1][i].ToString();
                    if (sValue.IndexOfAny(cHexa) >= 0)
                        b = iHexaNumeric[sHexa.IndexOf(sFraction[1][i])];
                    else
                        b = (int)sFraction[1][i] - asciiDiff;
                    result += b * (decimal)Math.Pow((double)numbase, iPow);
                }
                //string sResult = "0." + result.ToString();
                frac = result;
            }
            return dec + frac;
        }
        public static decimal decimalFractionToBinaryFraction(decimal input, int numbase)
        {
            string[] sInput = input.ToString().Split('.');
            int dec = int.Parse(sInput[0].ToString());
            string strBin = DecimalToBase(dec, 2);
            string strFraction = "0.";
            decimal cFlag = 0;
            string x1;
            decimal value1;
            string[] x2;
            string x3 = "";
            bool InfinityFlag = false;

            if (sInput.Length == 1)
                return decimal.Parse(strBin);

            while (cFlag != 1)
            {
                if (cFlag == 0)
                {
                    x1 = "0." + sInput[1].ToString();
                }
                else
                {
                    x1 = "0." + x3.ToString();
                }
                value1 = decimal.Parse(x1) * numbase;
                x2 = value1.ToString().Split('.');

                strFraction += x2[0];
                x3 = x2[1];
                if (strFraction.Length > 20)
                {
                    InfinityFlag = true;
                    cFlag = 1;
                }
                else
                {
                    cFlag = value1;
                }
            }

            if (InfinityFlag)
                return decimal.MaxValue;

            return decimal.Parse(strBin) + decimal.Parse(strFraction);
        }

        public static string GetBinaryOperation(decimal p, decimal p_2, string p_3)
        {
            decimal cValue1 = BaseToDecimal(p.ToString(),2);
            decimal cValue2 = BaseToDecimal(p_2.ToString(), 2);
            decimal cResult ;
            string[] sResult;
 
            switch (p_3)
            {
                case "+" :
                    cResult = cValue1 + cValue2;
                    sResult = cResult.ToString().Split('.');
                    if (sResult.Length > 1)
                    {
                        return decimalFractionToBinaryFraction(cResult, 2).ToString();
                    }
                    return DecimalToBase(cResult, 2);
                case "-":
                    cResult = cValue1 - cValue2;
                    sResult = cResult.ToString().Split('.');
                    if (sResult.Length > 1)
                    {
                        return decimalFractionToBinaryFraction(cResult, 2).ToString();
                    }
                    return DecimalToBase(cResult, 2);
                case "x":
                    cResult = cValue1 * cValue2;
                    sResult = cResult.ToString().Split('.');
                    if (sResult.Length > 1)
                    {
                        return decimalFractionToBinaryFraction(cResult, 2).ToString();
                    }
                    return DecimalToBase(cResult, 2);
                case "÷":
                    cResult = cValue1 / cValue2;
                    sResult = cResult.ToString().Split('.');
                    if (sResult.Length > 1)
                    {
                        return decimalFractionToBinaryFraction(cResult, 2).ToString();
                    }
                    return DecimalToBase(cResult, 2);                 

            }
            return "";
        }
        public static string GetFloatingPointNumber(decimal input)
        {
            string[] sInput = input.ToString().Split('.');
            int iLength;
            decimal xOutput = 0;
            string sDivide = "1";
            string result = "";

            if ( input > 0 && input >= (decimal)0.1 && input < 1 )            
                return "+" + input.ToString() + " x 10^0";
            
            if ( input < 0 )
            {
                string mInput = input.ToString().Substring(1);
                if( decimal.Parse(mInput) >= (decimal)0.1 && decimal.Parse(mInput) < 1)
                    return input.ToString() + " x 10^0";
            }
           
            if (sInput[0] == "0" || sInput[0] == "-0")
            {
                iLength = sInput[1].Length;
                int c = 0;
                for (int i = 0; i < iLength-1; i++)
                {
                    if (xOutput >= (decimal)0.1 && xOutput < 1)
                        break;
                    sDivide += "0";
                    c--;
                    if (sInput[0].Substring(0, 1) == "-")
                    {
                        string m = input.ToString().Substring(1);
                        xOutput = (decimal)(decimal.Parse(m) * int.Parse(sDivide));
                    }
                    else
                    {
                        xOutput = (decimal)(input * int.Parse(sDivide));
                    }
                }
                iLength = 0 - (iLength - 1);
                xOutput = input * int.Parse(sDivide);
                result = xOutput.ToString() + " x 10^" +c.ToString();
            }
            else
            {
                iLength = sInput[0].Length;
                if (input < 0)
                    iLength -= 1;

                for (int i = 0; i < iLength; i++)
                {
                    sDivide += "0";
                }

                xOutput = input / int.Parse(sDivide);


                result = xOutput.ToString() + " x 10^" + iLength.ToString();
            }
            if (input > 0)
                result = "+" + result;
            return result;
        }

        public static bool IsBinaryNumber(string num)
        {
            //bool result = true;
            //int dotCount = 0;
            if (num.ToString() == "1" || num.ToString() == "0" )
            {
                return true;
            }
            if (num.ToString() == ".")
            {
                return true;
            }
            else
            {
                return false;
            }
            
            
        }

        public static bool IsDecimalFractionNumber(string num)
        {
            bool result = true;
            int dotCount = 0;
            foreach (char c in num.ToString().ToCharArray())
            {
                if (char.IsDigit(c))
                {
                    return true;
                }
                if (c.ToString() == ".")
                {
                    dotCount++;
                }
                else
                {
                    result = false;
                }
            }
            if (dotCount > 1)
                return false;

            return result;
        }
        public static bool IsHexadecimalNumber(string num)
        {
            bool result = false;
            int dotCount = 0;
            foreach (char c in num.ToCharArray())
            {                
                if (!char.IsDigit(c))
                {
                    if (c.ToString() == ".")
                    {
                        dotCount++;
                        result = true;
                    }
                    else
                    {
                        result = IsHexa(c.ToString());
                        if (result == false)
                            return result;
                    }
                }
                else
                {
                    result = true;
                }
            }
            if (dotCount > 1)
                return false;

            return result;
        }
        public static bool IsOctalNumber(string num)
        {
            bool result = false;
            int dotCount = 0;
            foreach (char c in num.ToCharArray())
            {
                int i = 0;
                if( int.TryParse (c.ToString(),out i) && i < 8)
                {
                    result = true;
                }
                else
                {
                    if (c.ToString() == ".")
                    {
                        dotCount++;
                        result = true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }

            if (dotCount > 1)
                return false;

            return result;
        }
        private static bool IsHexa(string p)
        {
            
            foreach (char item in cHexa)
            {
                if (p.ToUpper() == item.ToString())
                {
                    return true;
                    
                }
            }
            return false;
        }
    }
}
